package com.google.ant.extensions.tasks.optional;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import com.google.ant.extensions.tasks.AbstractFantTask;
import com.google.util.FileUtils;

import org.apache.tools.ant.taskdefs.Java;
import org.apache.tools.ant.types.CommandlineJava;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;

public class Wsdl2JavaTask extends AbstractFantTask {

    private static final String DEFAULT_WSDL2JAVA_CLASS = "org.apache.cxf.tools.wsdlto.WSDLToJava";
    private static final String MAIN_WSDL_DIR = "src.main.wsdl.dir";

    private static final String WSDL_SUFFIX = ".+\\.wsdl$";
    private static final String WSDL_OPTIONS = "-options$";
    private static final String WSDL_BINDINGS = "-binding-?\\d*.xml$";

    private static final String WSDL_LIB_DIR = "wsdl2java.lib.dir";

    private static final String DONE_SUFFIX = ".DONE";

    protected File srcdir;

    public void setSrcdir(File to) {
        this.srcdir = to;
    }

    public void execute() {
        File mainWsdlDir = srcdir;
        if (mainWsdlDir == null) {
            mainWsdlDir = new File(getProject().getProperty(MAIN_WSDL_DIR));
        }

        List<List<String>> jobs = findJobs(mainWsdlDir, getWsdlFiles(mainWsdlDir));

        for (List<String> job : jobs) {
            wsdl2java(job);
        }
    }

    private void wsdl2java(List<String> args) {
        if (args.size() == 0) {
            return;
        }
        try {
            Java java = new Java();
            java.setProject(getProject());
            java.setTaskName("fant.wsdl2java");
            java.setFork(true);

            java.setClassname(DEFAULT_WSDL2JAVA_CLASS);

            CommandlineJava command = java.getCommandLine();
            java.createArg().setLine(toLine(args));

            FileSet fileSet = new FileSet();
            fileSet.setDir(new File(getProject().getProperty(WSDL_LIB_DIR)));
            fileSet.setIncludes("*.jar");
            
            Path path = command.createClasspath(getProject());
            path.addFileset(fileSet);

            java.execute();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        
        touch(getDoneFile(new File(args.get(args.size() - 1))));
    }

    private String toLine(List<String> args) {
        StringBuffer sb = new StringBuffer();
        for (String v : args) {
            sb.append(v);
            sb.append(" ");
        }
        return sb.toString();
    }

    private List<File> getWsdlFiles(File dir) {
        return FileUtils.getFiles(dir, WSDL_SUFFIX);
    }

    private File getOptions(File dir, String pattern) {
        List<File> files = FileUtils.getFiles(dir, pattern);
        if (files.size() > 0) {
            return files.iterator().next();
        }
        return null;
    }

    private List<File> getBindingFiles(File dir, String pattern) {
        return FileUtils.getFiles(dir, pattern);
    }

    protected List<List<String>> findJobs(File dir, List<File> wsdlFiles) {
        List<List<String>> jobs = new ArrayList<List<String>>();

        for (File wsdl : wsdlFiles) {
            if (wsdl == null || !wsdl.exists()) {
                continue;
            }

            File done = getDoneFile(wsdl);
            if (done.exists() && wsdl.lastModified() <= done.lastModified()) {
                if (verbose) {
                    System.out.println(wsdl + " already DONE!");
                }
                continue;
            }

            String wsdlName = wsdl.getName();
            wsdlName = wsdlName.substring(0, wsdlName.indexOf(".wsdl"));
            File options = getOptions(dir, wsdlName + WSDL_OPTIONS);
            List<File> bindings = getBindingFiles(dir, wsdlName + WSDL_BINDINGS);

            jobs.add(getArguments(wsdl, bindings, options));
        }
        return jobs;
    }

    protected File getDoneFile(File wsdl) {
        return new File(destdir, wsdl.getName() + DONE_SUFFIX);
    }

    protected List<String> getArguments(final File wsdl, 
                                        final List<File> bindingFiles, 
                                        final File options) {
        List<String> arguments = new ArrayList<String>();

        if (verbose) {
            arguments.add("-V");
        }

        arguments.add("-d");
        arguments.add(destdir.toString());

        if (bindingFiles != null) {
            for (File binding : bindingFiles) {
                arguments.add("-b");
                arguments.add(binding.toString());
            }
        }

        if (options != null && options.exists()) {
            try {
                List<String> lines = FileUtils.readLines(options);
                if (lines.size() > 0) {
                    arguments.add(lines.iterator().next());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        arguments.add(wsdl.toString());
        
        return arguments;
    }
}